package com.magenta.maxoptra.geocoding.yahoo.mapping;

import com.magenta.maxoptra.gis.GeoAddress;
import com.magenta.maxoptra.gis.GeoException;
import com.magenta.mrs.geocoding.mapping.XmlMappingFunctor;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;
/*
* Project: Maxoptra
* Author: Kirill Sychin
* Date: 01.11.2008 17:34:23
*
* Copyright (c) 1999-2008 Magenta Corporation Ltd. All Rights Reserved.
* Magenta Technology proprietary and confidential.
* Use is subject to license terms.
*/

public class XmlYahooMappingFunctor implements XmlMappingFunctor<List<GeoAddress>> {
    private static final XmlYahooMappingFunctor _instance = new XmlYahooMappingFunctor();

    private List<String> accuracies;

    public static XmlYahooMappingFunctor getInstance() {
        return _instance;
    }

    private static final String Latitude = "Latitude";
    private static final String Longitude = "Longitude";
    private static final String Address = "Address";
    private static final String City = "City";
    private static final String State = "State";
    private static final String Zip = "Zip";
    private static final String Country = "Country";
    private static final String Precision = "precision";

    public List<GeoAddress> execute(String xml) throws GeoException {

        List<GeoAddress> res = new ArrayList<GeoAddress>();
        try {
            DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();

            ByteArrayInputStream in = new ByteArrayInputStream(xml.getBytes("UTF-8"));
            Document doc = docBuilder.parse(in);
            doc.getDocumentElement().normalize();

            NodeList listOfResult = doc.getElementsByTagName("Result");
            for (int s = 0; s < listOfResult.getLength(); s++) {

                Node nodes = listOfResult.item(s);
                if (nodes.getNodeType() == Node.ELEMENT_NODE) {

                    if (accuracies != null) {
                        Node precAttrNode = nodes.getAttributes().getNamedItem(Precision);
                        if (precAttrNode == null || precAttrNode.getTextContent() == null) {
                            throw new GeoException("There is no attribute \"" + Precision +
                                    "\" at the place in Yahoo Geocode XML there it is expected");
                        }
                        accuracies.add(precAttrNode.getTextContent());
                    }

                    GeoAddress geoAddress = new GeoAddress();
                    for (int i = 0; i < nodes.getChildNodes().getLength(); i++) {
                        Node property = nodes.getChildNodes().item(i);
                        if (property.getNodeName().equals(Latitude)) {
                            geoAddress.setLatitude(Double.valueOf(property.getTextContent()));
                        } else if (property.getNodeName().equals(Longitude)) {
                            geoAddress.setLongitude(Double.valueOf(property.getTextContent()));
                        } else if (property.getNodeName().equals(Country)) {
                            geoAddress.setCountry(property.getTextContent());
                        } else if (property.getNodeName().equals(City)) {
                            geoAddress.setCity(property.getTextContent());
                        } else if (property.getNodeName().equals(Address)) {
                            geoAddress.setStreet(property.getTextContent());
                        } else if (property.getNodeName().equals(Zip)) {
                            geoAddress.setZip(property.getTextContent());
                        } else if (property.getNodeName().equals(State)) {
                            geoAddress.setState(property.getTextContent());
                        }
                    }
                    res.add(geoAddress);

                }
            }
        } catch (SAXParseException err) {
            System.out.println("** Parsing error" + ", line "
                    + err.getLineNumber() + ", uri " + err.getSystemId());
            System.out.println(" " + err.getMessage());
        } catch (SAXException e) {
            Exception x = e.getException();
            ((x == null) ? e : x).printStackTrace();
        } catch (Throwable t) {
            t.printStackTrace();
        }

        return res;
    }

    public void setAccuracies(List<String> accuracies) {
        this.accuracies = accuracies;
    }
}
